﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using System.Media;

namespace eBrain
{
    public partial class Exp_MultipleChoice : Experiment
    {
        public bool UseMultipleSelectionsPerTrial = false;
        public bool UpdateSpellerMenu = false;
        public double SumVal;
        /// <summary>
        /// Numero di selezioni effettuate nel presente Trial (pensato per scelte multiple nello stesso trial)
        /// </summary>
        public int ActTrialNumOfSelections = 0;

        /// <summary>
        /// Numero massimo di selezioni per un dato Trial
        /// </summary>
        public int MaxSelectionsPerTrial = 1;

        public Exp_MultipleChoice(TestControlWindow _tcw, ExperimentMainForm _expw)//, int _w, int _h)
            : base(_tcw, _expw)//, _w, _h) 
        { }

        public Exp_MultipleChoice(ExperimentMainForm _expw, string datapath, string logpath, string sInputMode)
            : base(_expw, datapath, logpath, sInputMode)//, _w, _h) 
        { }

        public override void CustomXMLLoad(XmlDocument xmldoc)
        {
            UseMultipleSelectionsPerTrial = bool.Parse(xmldoc.SelectSingleNode("Experiment/UseMultipleSelectionsPerTrial").InnerText);
            UpdateSpellerMenu = bool.Parse(xmldoc.SelectSingleNode("Experiment/UpdateSpellerMenu").InnerText);
        }

        public override void Custom_DoNextTrial()
        {
            SumVal = 0;

            //verifico se devo inviare il comando di aggiornamento del menu al P300SPeller
            if (UpdateSpellerMenu && ExpInputMode == InputMode.P300Speller)
            {
                string s = sSpellerMenu + (ActualTrialNumber + 1).ToString() + "\n";
                SendUDPString(s);
                Thread.Sleep(100);
                SendUDPString(PauseOff);
                Thread.Sleep(100);
                SendUDPString(PauseOn);
            }

            base.Custom_DoNextTrial();
        }

        public override void UpdateCanvas()
        {
            int x, y, w, h, x0, y0, w1, h1;
            string sx, sy;
            string imgfile = "";
            //string audiofile = "";
            string text = "";

            try
            {
                if (bConstantRois)
                {

                    //Le ROI sono costanti, seleziono il Trial
                    UpdateConstantROIList();

                    UpdateCanvasMtx.WaitOne();

                    Graphics CanvasGraphics = Graphics.FromImage(WorkingCanvas);
                    CanvasGraphics.Clear(bkgrnd);

                    XmlNodeList TrialROIList;
                    if (bTrainingMode)
                        TrialROIList = TrainingTrials.Item(ActualTrialNumber).SelectNodes("ROIs/ROI");
                    else
                        TrialROIList = Trials.Item(ActualTrialNumber).SelectNodes("ROIs/ROI");

                    for (int k = 0; k < ROIs.Count; k++)
                    {
                        bool active = bool.Parse(ROIs.Item(k).SelectSingleNode("active").InnerText.ToString());
                        if (ExpInputMode != InputMode.P300Speller || !active)
                        {
                            //Calcolo i dati geometrici
                            w = int.Parse(ROIs.Item(k).SelectSingleNode("w").InnerText.ToString());
                            h = int.Parse(ROIs.Item(k).SelectSingleNode("h").InnerText.ToString());

                            sx = ROIs.Item(k).SelectSingleNode("x").InnerText.ToString();
                            sy = ROIs.Item(k).SelectSingleNode("y").InnerText.ToString();

                            x = int.Parse(sx.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, ""));
                            y = int.Parse(sy.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, ""));

                            x0 = (x * ScreenWidth) / 100;
                            y0 = (y * ScreenHeight) / 100;
                            //x =  x0 - w / 2;
                            //y =  y0 - h / 2;

                            //<DataViewer> 
                            if (bEyelinkConnected)
                            {
                                string sID = ROIs.Item(k).SelectSingleNode("ID").InnerText.ToString();

                                ET.SendMessage("!V IAREA RECTANGLE " + (k + 1).ToString() + " " +
                                     (x0 - w / 2).ToString() + " " +
                                     (y0 - h / 2).ToString() + " " +
                                     (x0 + w / 2).ToString() + " " +
                                     (y0 + h / 2).ToString() + " " +
                                     sID);
                            }

                            if (bConstantROIImages)
                                imgfile = ROIs.Item(k).SelectSingleNode("img").InnerText.ToString();
                            else
                            {
                                imgfile = TrialROIList.Item(k).SelectSingleNode("img").InnerText.ToString();
                                text = TrialROIList.Item(k).SelectSingleNode("text").InnerText.ToString();
                                //ROIs.Item(k).Value = TrialROIList.Item(k).Value;
                            }

                            if (imgfile != "")
                            {
                                Image myImag = Image.FromFile(sImagePath + imgfile);
                                w1 = myImag.Width;
                                h1 = myImag.Height;
                                x = x0 - w1 / 2;
                                y = y0 - h1 / 2;

                                //myImag.HorizontalResolution

                                CanvasGraphics.DrawImage(myImag, x, y, w, h);

                                //<DataViewer> se è connesso l'eyetracker, spedisco il comando per disegnare l'mmagine nel dataviewer
                                if (bEyelinkConnected)
                                {
                                    ET.SendMessage("!V IMGLOAD TOP_LEFT " + sImagePath + imgfile + x.ToString() + " " + y.ToString());
                                }

                                //e.Graphics.DrawLine(new Pen(frgrnd), x0, 0, x0, 800);
                                //graphicsObj.DrawLine(myPen, 0, 0, 1000, 400);
                            }
                            else if (text != "")
                            {
                                x = x0 - w / 2;
                                y = y0 - h / 2;

                                //TODO: da inserire nei file di configurazione
                                using (Font font1 = new Font("Arial", 22, FontStyle.Bold, GraphicsUnit.Point))
                                {
                                    Rectangle rect1 = new Rectangle(x, y, w, h);

                                    StringFormat stringFormat = new StringFormat();
                                    stringFormat.Alignment = StringAlignment.Center;
                                    stringFormat.LineAlignment = StringAlignment.Center;
                                    SolidBrush sb = new SolidBrush(frgrnd);

                                    // Draw the text and the surrounding rectangle.
                                    CanvasGraphics.DrawString(text, font1, sb, rect1, stringFormat);

                                    //TextFormatFlags flags = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter;
                                    //TextRenderer.DrawText(CanvasGraphics, text, font1, rect1, frgrnd, flags);


                                    //e.Graphics.DrawString(text, font1, Brushes.Blue, rectF1,);
                                    //e.Graphics.DrawRectangle(Pens.White, Rectangle.Round(rectF1));
                                }
                            }
                        }
                    }
                    CanvasGraphics.Dispose();
                    myExpW.CopyImage(WorkingCanvas);

                    UpdateCanvasMtx.ReleaseMutex();
                    //myExpW.UnlockCanvasUserCopy();

                    //GraphMutex.ReleaseMutex();
                    //}
                }
                else
                {
                    //siamo in condizione di elenco ROI variabile

                    //Le ROI sono costanti, seleziono il Trial
                    UpdateVariableROIList();

                    UpdateCanvasMtx.WaitOne();

                    Graphics CanvasGraphics = Graphics.FromImage(WorkingCanvas);
                    CanvasGraphics.Clear(bkgrnd);

                    XmlNodeList TrialROIList;
                    if (bTrainingMode)
                        TrialROIList = TrainingTrials.Item(ActualTrialNumber).SelectNodes("ROIs/ROI");
                    else
                        TrialROIList = Trials.Item(ActualTrialNumber).SelectNodes("ROIs/ROI");


                    for (int k = 0; k < TrialROIList.Count; k++)
                    {

                        bool active = bool.Parse(TrialROIList.Item(k).SelectSingleNode("active").InnerText.ToString());
                        if (ExpInputMode != InputMode.P300Speller || !active)
                        {

                            //Calcolo i dati geometrici
                            w = int.Parse(TrialROIList.Item(k).SelectSingleNode("w").InnerText.ToString());
                            h = int.Parse(TrialROIList.Item(k).SelectSingleNode("h").InnerText.ToString());

                            sx = TrialROIList.Item(k).SelectSingleNode("x").InnerText.ToString();
                            sy = TrialROIList.Item(k).SelectSingleNode("y").InnerText.ToString();

                            x = int.Parse(sx.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, ""));
                            y = int.Parse(sy.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, ""));

                            x0 = (x * ScreenWidth) / 100;
                            y0 = (y * ScreenHeight) / 100;
                            //x =  x0 - w / 2;
                            //y =  y0 - h / 2;

                            //<DataViewer> 
                            if (bEyelinkConnected)
                            {
                                string sID = TrialROIList.Item(k).SelectSingleNode("ID").InnerText.ToString();

                                ET.SendMessage("!V IAREA RECTANGLE " + (k + 1).ToString() + " " +
                                     (x0 - w / 2).ToString() + " " +
                                     (y0 - h / 2).ToString() + " " +
                                     (x0 + w / 2).ToString() + " " +
                                     (y0 + h / 2).ToString() + " " +
                                     sID);
                            }

                            //TODO: da rivedere per gli elementi che sono NULL  
                            // es. http://stackoverflow.com/questions/1173177/c-sharp-xmlelement-selectsinglenode-returns-null-for-empty-string)

                            imgfile = TrialROIList.Item(k).SelectSingleNode("img").InnerText.ToString();


                            //text = TrialROIList.Item(k).SelectSingleNode("text").InnerText.ToString();

                            //ROIs.Item(k).Value = TrialROIList.Item(k).Value;

                            if (imgfile != "")
                            {
                                Image myImag = Image.FromFile(sImagePath + imgfile);
                                w1 = myImag.Width;
                                h1 = myImag.Height;
                                x = x0 - w1 / 2;
                                y = y0 - h1 / 2;

                                //myImag.HorizontalResolution

                                CanvasGraphics.DrawImage(myImag, x, y, w, h);

                                //<DataViewer> se è connesso l'eyetracker, spedisco il comando per disegnare l'mmagine nel dataviewer
                                if (bEyelinkConnected)
                                {
                                    ET.SendMessage("!V IMGLOAD TOP_LEFT " + sImagePath + imgfile + x.ToString() + " " + y.ToString());
                                }

                                //e.Graphics.DrawLine(new Pen(frgrnd), x0, 0, x0, 800);
                                //graphicsObj.DrawLine(myPen, 0, 0, 1000, 400);
                            }
                            else if (text != "")
                            {
                                x = x0 - w / 2;
                                y = y0 - h / 2;

                                //TODO: da inserire nei file di configurazione
                                using (Font font1 = new Font("Arial", 22, FontStyle.Bold, GraphicsUnit.Point))
                                {
                                    Rectangle rect1 = new Rectangle(x, y, w, h);

                                    StringFormat stringFormat = new StringFormat();
                                    stringFormat.Alignment = StringAlignment.Center;
                                    stringFormat.LineAlignment = StringAlignment.Center;
                                    SolidBrush sb = new SolidBrush(frgrnd);

                                    // Draw the text and the surrounding rectangle.
                                    CanvasGraphics.DrawString(text, font1, sb, rect1, stringFormat);

                                    //TextFormatFlags flags = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter;
                                    //TextRenderer.DrawText(CanvasGraphics, text, font1, rect1, frgrnd, flags);


                                    //e.Graphics.DrawString(text, font1, Brushes.Blue, rectF1,);
                                    //e.Graphics.DrawRectangle(Pens.White, Rectangle.Round(rectF1));
                                }
                            }
                        }
                    }
                    CanvasGraphics.Dispose();
                    myExpW.CopyImage(WorkingCanvas);

                    UpdateCanvasMtx.ReleaseMutex();

                }
                //Custom_UpdateCanvas(CanvasGraphics);


                //else
                //{

                //    //Le ROI non sono costanti. verifico in quale caso stiamo 
                //    UpdateVariableROIList();

                //    //bUpdatingCanvas = false;


                //}
                //exp_status = old_status;
                //mtx.ReleaseMutex();

            }
            catch (Exception ex)
            {
                MessageBox.Show("Update Canvas Error: " + ex.Message.ToString() + "\r\n" + ex.StackTrace);
            }
        }


        public override void TimeoutTimer_Elapsed(object obj, EventArgs e)
        {

            myResultList.Add(new ResultListElement(SumVal, "T", "Timeout"));

            NumOfTimeout++;

            TimeoutTimer.Stop();
            StopPeriodicTimer();

            //NumOfLetters++;

            myLog.Log("Trial " + ActualTrialNumber.ToString() + " Timout : ");

            if (bUseSounds)
            {
                //SoundPlayer sp = new SoundPlayer(Properties.Resources.timeout_future);
                SPTimeout.Play();
            }

            //<DataViewer>
            if (bEyelinkConnected)
                ET.SendCommand("TRIAL_RESULT 0");

            if (bTrainingMode)
            {
                if (++ActualTrialNumber >= TrainingTrials.Count)
                    FromTrainingToTrials();
                else
                {
                    DoNextTrial();
                }
            }
            else
            {
                if (++ActualTrialNumber >= Trials.Count)
                {
                    ActualTrialNumber = Trials.Count - 1;
                    EndOfTrials = true;

                    //SaveResults();
                    EndOfTest();
                }
                else
                {
                    DoNextTrial();
                }
            }
        }



        /// <summary>
        /// GEstisco la selezione che è stata richiamata dal gestore di eventi
        /// 
        /// VECCHIA VERSIONE (SENZA LA VERIFICA DELLA SELEZIONE DEGLI ITEM)
        /// </summary>
        //public override void SelectionHandler______Old()
        //public void SelectionHandler______Old()
        //{
        //    String s = "";
        //    int val = 0;
        //    int roi_selected = ROI_Selected;

        //    if (bUseSounds)
        //    {
        //        SPSelection.PlaySync();
        //        Thread.Sleep(50);
        //    }

        //    lock (myROIList)
        //    {

        //        //TODO: da verificare
        //        if (ExpInputMode == InputMode.P300Speller)
        //        {
        //            s = myROIList.myRoiList[roi_selected].sTag;
        //            val = myROIList.myRoiList[roi_selected].iValue;

        //            myExpW.UpdateSelectedArea(myROIList.myRoiList[roi_selected].x0, myROIList.myRoiList[roi_selected].y0,
        //               myROIList.myRoiList[roi_selected].width, myROIList.myRoiList[roi_selected].height,
        //               HighlightSelectionColor, iHighlightSelectionSize);
                    
        //            ////lo segnalo all'oggetto form, con una persistenza di 1000 ms (TODO: verificare che sia adatta)
        //            //myExpW.Invoke(new EventHandler(delegate
        //            //{
        //            //    myTranspLayer.UpdateP3WinSelectedArea(myROIList.myRoiList[roi_selected].x0, myROIList.myRoiList[roi_selected].y0,
        //            //    myROIList.myRoiList[roi_selected].width, myROIList.myRoiList[roi_selected].height,
        //            //    HighlightSelectionColor, iHighlightSelectionSize, HighlightSelectionTime);//, 1000);

        //            //}));
        //        }
        //        else
        //        {
        //            //NOn stiamo usando il P300Speller

        //            s = myROIList.GD_AreaSelected.tag;
        //            val = myROIList.GD_AreaSelected.value;

        //            //lo segnalo all'oggetto form, con una persistenza di 1000 ms (TODO: verificare che sia adatta)
        //            myExpW.UpdateSelectedArea(myROIList.GD_AreaSelected.x, myROIList.GD_AreaSelected.y,
        //                myROIList.GD_AreaSelected.w, myROIList.GD_AreaSelected.h,
        //                HighlightSelectionColor, iHighlightSelectionSize);//, 1000);

        //            myExpW.Invoke(new EventHandler(delegate { myExpW.Refresh(); }));

        //            //TODO: verificare che non ci sia da mettere qui un tempo di attesa

        //            myExpW.TurnOffSelectedArea();
        //            myExpW.TurnOffInROIArea();

        //        }
        //    }


        //    myLog.Log("Selection Handler - Target selected: " + s);



        //    bROISelected = false;

        //    //resetto la roi selezionata
        //    ROI_Selected = RoiList.NO_ROI;

        //    //<DataViewer>
        //    if (bEyelinkConnected)
        //        ET.SendCommand("TRIAL_RESULT 0");

        //    if (UseMultipleSelectionsPerTrial)
        //    {
        //        if (bTrainingMode)
        //            MaxSelectionsPerTrial = int.Parse(TrainingTrials.Item(ActualTrialNumber).SelectSingleNode("SelectionsPerTrial").InnerText);
        //        else
        //            MaxSelectionsPerTrial = int.Parse(Trials.Item(ActualTrialNumber).SelectSingleNode("SelectionsPerTrial").InnerText);

        //        SumVal += val / (double)MaxSelectionsPerTrial;

        //    }
        //    else
        //    {
        //        SumVal += val;
        //        //myResultList.Add(new ResultListElement(val, s, ""));

        //    }

        //    ActTrialNumOfSelections++;

        //    if (ActTrialNumOfSelections >= MaxSelectionsPerTrial)
        //    {
        //        //azzero il numero di selezioni per il dato trial
        //        ActTrialNumOfSelections = 0;

        //        myResultList.Add(new ResultListElement(SumVal, s, ""));
        //        TrialScore += (int)Math.Round(SumVal, 0);


        //        if (bTrainingMode)
        //        {

        //            if (++ActualTrialNumber >= TrainingTrials.Count)
        //                FromTrainingToTrials();
        //            else
        //                DoNextTrial();
        //        }

        //        else
        //        {

        //            if (++ActualTrialNumber >= Trials.Count)
        //            {
        //                ActualTrialNumber = Trials.Count - 1;
        //                EndOfTrials = true;

        //                EndOfTest();
        //                //SaveResults();
        //                //EndOfTest();
        //            }
        //            else
        //            {
        //                //TODO: mettere a posto perchp qui non va benissimo - solo per prova
        //                DoNextTrial();
        //                //UpdateCanvas();
        //                //this.Invalidate();
        //            }
        //        }
        //    }
        //}

        /// <summary>
        /// GEstisco la selezione che è stata richiamata dal gestore di eventi
        /// 
        /// NUOVA VERSIONE CON LA VERIFICA DELLA SELEZIONE PROPOSTA DALLA MACCHINA
        /// </summary>
        public override void SelectionHandler()
        {
            //String s = "";
            //int val = 0;
            int roi_selected = ROI_Selected;

            if (bUseSounds)
            {
                SPSelection.PlaySync();
                Thread.Sleep(50);
            }

            lock (myROIList)
            {

                //TODO: da verificare
                if (ExpInputMode == InputMode.P300Speller)
                {
                    //s = myROIList.myRoiList[roi_selected].sTag;
                    //val = myROIList.myRoiList[roi_selected].iValue;

                    //lo segnalo all'oggetto form, con una persistenza di 1000 ms (TODO: verificare che sia adatta)
                    myExpW.Invoke(new EventHandler(delegate
                    {
                        //myExpW.ManageHighlightSelection(myROIList, ROI_Selected, 0, myROIList.myRoiList.Count - 1, HighlightSelectionColor, iHighlightSelectionSize);
                        if (myROIList.myRoiList[0].bActive)
                        {
                            min_ROI_ID = 0;
                            max_ROI_ID = myROIList.myRoiList.Count - 1;
                        }
                        else
                        {
                            min_ROI_ID = 1;
                            max_ROI_ID = myROIList.myRoiList.Count;
                        }

                        myTranspLayer.ManageHighlightSelection(myROIList, ROI_Selected, HighlightSelectionColor, iHighlightSelectionSize);

                        //myExpW.Refresh();

                        //myTranspLayer.UpdateP3WinSelectedArea_Step1(myROIList.myRoiList[roi_selected].x0, myROIList.myRoiList[roi_selected].y0,
                        //myROIList.myRoiList[roi_selected].width, myROIList.myRoiList[roi_selected].height,
                        //HighlightSelectionColor, iHighlightSelectionSize);//, 1000);

                    }));

                    //bVerifySelection = true; 

                }
                else
                {
                    //NOn stiamo usando il P300Speller

                    //s = myROIList.GD_AreaSelected.tag;
                    //val = myROIList.GD_AreaSelected.value;

                    //lo segnalo all'oggetto form, con una persistenza di 1000 ms (TODO: verificare che sia adatta)
                    myExpW.UpdateSelectedArea(myROIList.GD_AreaSelected.x, myROIList.GD_AreaSelected.y,
                        myROIList.GD_AreaSelected.w, myROIList.GD_AreaSelected.h,
                        HighlightSelectionColor, iHighlightSelectionSize);//, 1000);

                    myExpW.Invoke(new EventHandler(delegate { myExpW.Refresh(); }));

                    //TODO: verificare che non ci sia da mettere qui un tempo di attesa

                    myExpW.TurnOffSelectedArea();
                    myExpW.TurnOffInROIArea();


                    PerformSelection();

                }

            }

        }

        public override void PerformSelection()
        {
            string s = "";
            int val = 0;

            if (ExpInputMode == InputMode.P300Speller)
            {
                s = myROIList.myRoiList[ROI_Selected].sItem;
                val = myROIList.myRoiList[ROI_Selected].iValue;
            }
            else
            {
                s = myROIList.GD_AreaSelected.item;
                val = myROIList.GD_AreaSelected.value;
            }

            myLog.Log("PerformSelection - Target selected: " + s);

            bROISelected = false;

            //resetto la roi selezionata
            ROI_Selected = RoiList.NO_ROI;

            //<DataViewer>
            if (bEyelinkConnected)
                ET.SendCommand("TRIAL_RESULT 0");

            if (UseMultipleSelectionsPerTrial)
            {
                if (bTrainingMode)
                    MaxSelectionsPerTrial = int.Parse(TrainingTrials.Item(ActualTrialNumber).SelectSingleNode("SelectionsPerTrial").InnerText);
                else
                    MaxSelectionsPerTrial = int.Parse(Trials.Item(ActualTrialNumber).SelectSingleNode("SelectionsPerTrial").InnerText);

                SumVal += val / (double)MaxSelectionsPerTrial;
            }
            else
            {
                SumVal += val;
                //myResultList.Add(new ResultListElement(val, s, ""));
            }

            ActTrialNumOfSelections++;

            if (ActTrialNumOfSelections >= MaxSelectionsPerTrial)
            {
                //azzero il numero di selezioni per il dato trial
                ActTrialNumOfSelections = 0;

                myResultList.Add(new ResultListElement(SumVal, s, ""));
                TrialScore += (int)Math.Round(SumVal, 0);

                if (bTrainingMode)
                {

                    if (++ActualTrialNumber >= TrainingTrials.Count)
                        FromTrainingToTrials();
                    else
                        DoNextTrial();
                }

                else
                {

                    if (++ActualTrialNumber >= Trials.Count)
                    {
                        ActualTrialNumber = Trials.Count - 1;
                        EndOfTrials = true;

                        EndOfTest();
                        //SaveResults();
                        //EndOfTest();
                    }
                    else
                    {
                        //TODO: mettere a posto perchp qui non va benissimo - solo per prova
                        DoNextTrial();
                        //UpdateCanvas();
                        //this.Invalidate();
                    }
                }
            }
        }
    }
}
